﻿using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NewRetail.Application.Components.TianQue.Configurations;
using NewRetail.Application.Components.TianQue.Entity;
using NewRetail.Application.Components.TianQue.Model;
using NewRetail.Application.Core.Entity;
using NewRetail.Application.Utility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace NewRetail.Application.Components.TianQue.Services
{
    #region 天阙接口
    /// <summary>
    /// 天阙接口
    /// </summary>
    public interface ITianQueService : IApplicationService
    {
        /// <summary>
        /// 签名检验。
        /// </summary>
        /// <param name="respData">请求数据</param>
        /// <returns>检验成功则返回true，否则返回false。</returns>
        bool VerifyEventSignature(IDictionary<string, object> respData);
        /// <summary>
        /// 支付通知回调
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        Task<(bool, string)> TianQueNotifyResponseMessage(IDictionary<string, object> content);
        /// <summary>
        /// 天阙POS订单收银台支付
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        Task<(string, string)> SendTradePosPayOrderAsync(PosOrderInput inputDto);
        /// <summary>
        /// 天阙POS收银台订单状态查询
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        Task<(OnlinePosOrderQueryResponse, string)> QueryOnlineTradePosPayOrderAsync(OnlinePosOrderQueryInput inputDto);
        /// <summary>
        /// 查询本地数据库中天阙支付结果情况
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        Task<(string, string)> QueryLocalTradePosPayOrderAsync(LocalPosOrderQueryInput inputDto);
    }
    #endregion

    #region 实现
    /// <summary>
    /// 实现
    /// </summary>
    public class TianQueService : ApplicationService, ITianQueService
    {
        #region Field
        private readonly ILogger _logger;
        private readonly TianQueOptions _tianQueOptions;
        private readonly IRepository<TianQuePayRecordEntity> _tianQuePayRecordRep;
        protected IEntityHelper _entityHelper => this.LazyServiceProvider.LazyGetRequiredService<IEntityHelper>();
        private readonly IMapper _mapper;
        private readonly IHttpHelperService _httpHelperService;
        #endregion

        #region 构造函数
        public TianQueService(IRepository<TianQuePayRecordEntity> tianQuePayRecordRep, IOptions<TianQueOptions> tianQueOptions,
             IHttpHelperService httpHelperService, IMapper mapper, ILogger<TianQueService> logger)
        {
            _logger = logger;
            _tianQueOptions = tianQueOptions.Value;
            _tianQuePayRecordRep = tianQuePayRecordRep;
            _httpHelperService = httpHelperService;
            _mapper = mapper;
        }
        #endregion

        #region Implementation of ISignatureService

        #region 天阙支付回调相关

        #region 签名检验
        /// <summary>
        /// 签名检验。
        /// </summary>
        /// <param name="respData">请求数据</param>
        /// <returns>检验成功则返回true，否则返回false。</returns>
        public bool VerifyEventSignature(IDictionary<string, object> respData)
        {
            bool valid = false;
            try
            {
                //sign必须存在
                if (!respData.ContainsKey("sign"))
                    return valid;

                string signResult = respData["sign"].ToString();
                respData.Remove("sign");
                string resultStr = UtilsHelper.GetSignContent(respData);
                //组装加密串
                if (Cryptography.Verify(resultStr, signResult, _tianQueOptions.PublicKeyPem))
                    valid = true;
            }
            catch (Exception e)
            {
                _logger.LogError(message: e.Message, exception: e);
            }
            return valid;
        }
        #endregion

        #region 支付通知回调
        /// <summary>
        /// 支付通知回调
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public async Task<(bool, string)> TianQueNotifyResponseMessage(IDictionary<string, object> content)
        {
            var result = (true, "");
            try
            {
                var bizOrderInfo = new BizOrderDto();
                if (content.ContainsKey("bizOrderInfo"))
                {
                    //获取出bizOrderInfo对象
                    bizOrderInfo = UtilsHelper.DeserializeObject<BizOrderDto>(content["bizOrderInfo"].ToString());
                    //将此值移除掉
                    content.Remove("bizOrderInfo");
                }
                //字典转json字符串
                var strContent = UtilsHelper.SerializeObject(content);

                if (content.ContainsKey("tranType"))
                {
                    //卡交易
                    
                    //json字符串转对象
                    var objContent = UtilsHelper.DeserializeObject<PosSendNotifyCardDto>(strContent);
                    objContent.bizOrderInfo = bizOrderInfo;
                    //如果收到则直接存库
                    var db = await _tianQuePayRecordRep.GetDbContextAsync();
                    var tianQuePayRecord = await db.Set<TianQuePayRecordEntity>().FirstOrDefaultAsync(x => x.uuid == objContent.uuid);
                    if (tianQuePayRecord != null)
                    {
                        //有就更新
                        tianQuePayRecord.tranSts = objContent.tranSts;
                        _entityHelper.SetUpdationInfo(tianQuePayRecord);
                        await _tianQuePayRecordRep.UpdateAsync(tianQuePayRecord, autoSave: true);                        
                    }
                    else
                    {
                        //没有插入
                        var objRet = _mapper.Map<TianQuePayRecordEntity>(objContent);
                        _entityHelper.InitEntity(objRet);
                        await _tianQuePayRecordRep.InsertAsync(objRet, autoSave: true);
                    }
                }
                else
                {
                    //码交易
                    //json字符串转对象
                    var objContent = UtilsHelper.DeserializeObject<PosSendNotifyCodeDto>(strContent);
                    objContent.bizOrderInfo = bizOrderInfo;
                }
                //    //请求回调
                //    result = await _tianQueReplySetService.OnWriteOffEventRequest(content, client, merchantId);

                _logger.LogInformation("回调：" + content);
            }
            catch(Exception e)
            {
                result = (false, e.Message);
                _logger.LogError(message: e.Message, exception: e);
            }
            return result;
        }
        #endregion

        #endregion

        #region 天阙POS订单收银台支付
        /// <summary>
        /// 天阙POS订单收银台支付
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        public async Task<(string, string)> SendTradePosPayOrderAsync(PosOrderInput inputDto)
        {
            //创建一个Hashtable实例
            Hashtable ht = new Hashtable();

            //POS支付下单
            ht.Add("bizOrderNo", inputDto.bizOrderNo);
            ht.Add("mno", _tianQueOptions.Mno);
            ht.Add("bizAllAmt", inputDto.bizAllAmt);
            ht.Add("subject", inputDto.orderSubject);
            ht.Add("trmNo", inputDto.trmNo);

            TqApiRequestBeanDto apiRequestBean = new TqApiRequestBeanDto
            {
                orgId = _tianQueOptions.OrgId, //机构号
                reqId = Guid.NewGuid().ToString().Replace("-", ""),
                signType = _tianQueOptions.SignType,
                timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                version = "1.0",
                reqData = ht
            };

            string payUrl = string.Concat(_tianQueOptions.BaseUrl, "/order/pos/pOrder");
            string rsaResult;
            string requestMessage = "";
            // string result = JsonConvert.SerializeObject(requestMsgBody);
            //拼接字符串 xx=yy&kk=bb 格式
            string result = PackReflectionEntity<TqApiRequestBeanDto>.GetEntityToString(apiRequestBean);
            Console.Write("<br><br>签名串：" + result.Replace("&", "&amp;"));
            //签名
            rsaResult = Cryptography.Sign(result, _tianQueOptions.PrivateKeyPem);
            Console.Write("<br><br>签名：" + rsaResult);
            //实体付签名传给接口
            requestMessage = FillFullRequestMessage(rsaResult, apiRequestBean);
            string responseJson = null!;
            try
            {
                Console.Write("<br><br>请求参数：" + requestMessage);
                responseJson = await _httpHelperService.PostDfAsync(payUrl, requestMessage, false, "");//.Result;
                Console.Write("<br><br>返回参数：" + responseJson);
            }
            catch (Exception ex)
            {
                return (null, ex.Message);
            }
            IDictionary<string, object> respData = null;
            try
            {
                respData = UtilsHelper.DeserializeObject<Dictionary<string, object>>(responseJson);
                if (respData["code"].ToString() == "0000")
                {
                    string signResult = respData["sign"].ToString()!;
                    respData.Remove("sign");
                    string resultStr = UtilsHelper.GetSignContent(respData);
                    Console.Write("<br><br>返回参数签名串：" + resultStr);
                    //组装加密串
                    if (Cryptography.Verify(resultStr, signResult, _tianQueOptions.PublicKeyPem))
                    {
                        Console.Write("<br><br>本地验证签名成功");
                    }
                    else
                    {
                        Console.Write("<br><br>本地验证签名不成功");
                        return (responseJson, "本地验证签名不成功");
                    }
                }
            }
            catch (Exception ex)
            {
                return (null, ex.Message);
            }
            return (responseJson, null);
        }
        #endregion

        #region 天阙POS收银台订单状态查询
        /// <summary>
        /// 天阙POS收银台订单状态查询
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        public async Task<(OnlinePosOrderQueryResponse, string)> QueryOnlineTradePosPayOrderAsync(OnlinePosOrderQueryInput inputDto)
        {
            //创建一个Hashtable实例
            Hashtable ht = new Hashtable();

            //POS收银台订单状态
            ht.Add("mno", _tianQueOptions.Mno);
            ht.Add("bizOrderNo", inputDto.bizOrderNo);
            ht.Add("bizOrderType", inputDto.bizOrderType);

            TqApiRequestBeanDto apiRequestBean = new TqApiRequestBeanDto
            {
                orgId = _tianQueOptions.OrgId, //机构号
                reqId = Guid.NewGuid().ToString().Replace("-", ""),
                signType = _tianQueOptions.SignType,
                timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                version = "1.0",
                reqData = ht
            };

            string payUrl = string.Concat(_tianQueOptions.BaseUrl, "/order/pos/pQuery");
            string rsaResult;
            string requestMessage = "";
            //拼接字符串 xx=yy&kk=bb 格式
            string result = PackReflectionEntity<TqApiRequestBeanDto>.GetEntityToString(apiRequestBean);
            Console.Write("<br><br>签名串：" + result.Replace("&", "&amp;"));
            //签名
            rsaResult = Cryptography.Sign(result, _tianQueOptions.PrivateKeyPem);
            Console.Write("<br><br>签名：" + rsaResult);
            //实体付签名传给接口
            requestMessage = FillFullRequestMessage(rsaResult, apiRequestBean);
            string responseJson = null!;
            try
            {
                Console.Write("<br><br>请求参数：" + requestMessage);
                responseJson = await _httpHelperService.PostDfAsync(payUrl, requestMessage, false, "");//.Result;
                Console.Write("<br><br>返回参数：" + responseJson);
            }
            catch (Exception ex)
            {
                return (null, ex.Message);
            }
            IDictionary<string, object> respData = null;
            string strRespData = string.Empty;
            try
            {
                respData = UtilsHelper.DeserializeObject<Dictionary<string, object>>(responseJson);
                if (respData["code"].ToString() == "0000")
                {
                    string signResult = respData["sign"].ToString()!;
                    respData.Remove("sign");
                    string resultStr = UtilsHelper.GetSignContent(respData);
                    Console.Write("<br><br>返回参数签名串：" + resultStr);
                    //组装加密串
                    if (Cryptography.Verify(resultStr, signResult, _tianQueOptions.PublicKeyPem))
                    {
                        Console.Write("<br><br>本地验证签名成功");
                        strRespData = respData["respData"].ToString();
                    }
                    else
                    {
                        Console.Write("<br><br>本地验证签名不成功");
                        return (null, "本地验证签名不成功");
                    }
                }
            }
            catch (Exception ex)
            {
                return (null, ex.Message);
            }
            var resultObj = UtilsHelper.DeserializeObject<OnlinePosOrderQueryResponse>(strRespData);
            return (resultObj, null);
        }
        #endregion

        #region 查询本地数据库中天阙支付结果情况
        /// <summary>
        /// 查询本地数据库中天阙支付结果情况
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        public async Task<(string, string)> QueryLocalTradePosPayOrderAsync(LocalPosOrderQueryInput inputDto)
        {
            //直接查询本地库
            var db = await _tianQuePayRecordRep.GetDbContextAsync();
            var tianQuePayRecord = await db.Set<TianQuePayRecordEntity>().AsNoTracking().FirstOrDefaultAsync(x => x.bizOrderInfo.bizOrderNo == inputDto.flowNo);
            if (tianQuePayRecord != null && tianQuePayRecord.tranSts == "S")
                return ("支付成功", "");
            else
                return ("支付失败", "");
        }
        #endregion

        #endregion

        #region private method

        #region 组装
        /// <summary>
        /// 组装
        /// </summary>
        /// <param name="queryResult"></param>
        /// <param name="requestMsgBody"></param>
        /// <returns></returns>
        private string FillFullRequestMessage(string queryResult, TqApiRequestBeanDto requestMsgBody)
        {
            TqApiRequestBeanDto data = new TqApiRequestBeanDto();
            data.reqData = requestMsgBody.reqData;
            data.signType = requestMsgBody.signType;
            data.version = requestMsgBody.version;
            data.orgId = requestMsgBody.orgId;
            data.reqId = requestMsgBody.reqId;
            data.timestamp = requestMsgBody.timestamp;
            data.sign = queryResult;

            string result = Newtonsoft.Json.JsonConvert.SerializeObject(data);
            return result;
        }
        #endregion

        #endregion
    }
    #endregion
}
